package main

import (
	"context"
	"fmt"
	"os"
	"reflect"

	"github.com/urfave/cli/v3"
	"gopkg.in/yaml.v3"

	config "gitee.com/woodpile/wgs.ths.config.go"
)

func LoadConfig(ctx *cli.Context) error {
	setFlagLookupFunc(ctx)
	err := config.DefaultContext.RenderConfig()
	if err != nil {
		return fmt.Errorf("render config failed: %v", err)
	}
	return nil
}

func LoadConfigManually(ctx *cli.Context) error {
	if config.DefaultContext.Root() == nil {
		return fmt.Errorf("root config is nil")
	}

	setFlagLookupFunc(ctx)
	if err := config.GlobalRendererDefault.Render(reflect.ValueOf(GlobalConfig), config.DefaultContext.Root()); err != nil {
		return fmt.Errorf("render default config failed: %v", err)
	}
	if err := config.GlobalRendererFile.Render(reflect.ValueOf(GlobalConfig), config.DefaultContext.Root()); err != nil {
		return fmt.Errorf("render file config failed: %v", err)
	}
	if err := config.GlobalRendererEnv.Render(reflect.ValueOf(GlobalConfig), config.DefaultContext.Root()); err != nil {
		return fmt.Errorf("render env config failed: %v", err)
	}
	if err := config.GlobalRendererFlag.Render(reflect.ValueOf(GlobalConfig), config.DefaultContext.Root()); err != nil {
		return fmt.Errorf("render flag config failed: %v", err)
	}

	return nil
}

func main() {
	cmd := &cli.Command{
		Name: "main",
		Flags: []cli.Flag{
			&cli.IntFlag{
				Name:  "port",
				Value: 23001,
			},
		},
	}
	cmd.Commands = []*cli.Command{
		{
			Name: "db",
			Flags: []cli.Flag{
				&cli.StringFlag{
					Name:  "database",
					Value: "test_db",
				},
			},
			Action: func(ctx *cli.Context) error {
				if err := LoadConfig(ctx); err != nil {
					return err
				}
				fmt.Printf("db command\n")
				return nil
			},
		},
	}
	cmd.Action = func(ctx *cli.Context) error {
		if err := LoadConfig(ctx); err != nil {
			return err
		}
		fmt.Printf("main command\n")
		return nil
	}

	if err := cmd.Run(context.Background(), os.Args); err != nil {
		fmt.Fprintf(os.Stderr, "run cmd failed: %v\n", err)
		os.Exit(1)
	}

	fmt.Printf("\n== render config success\n")
	{
		// bs, err := json.MarshalIndent(GlobalConfig, "", "  ")
		bs, err := yaml.Marshal(GlobalConfig)
		if err != nil {
			fmt.Fprintf(os.Stderr, "marshal config failed: %v\n", err)
			os.Exit(1)
		}
		fmt.Printf("%s\n", bs)
	}
	// {
	// 	bs, err := json.MarshalIndent(GlobalConfig, "", "  ")
	// 	if err != nil {
	// 		fmt.Fprintf(os.Stderr, "marshal config failed: %v\n", err)
	// 		os.Exit(1)
	// 	}
	// 	fmt.Printf("%s\n", bs)
	// }
}

func setFlagLookupFunc(ctx *cli.Context) {
	// fmt.Printf("--------%s : %s (%v)\n", ctx.Command.Name, ctx.String("ppp"), ctx.IsSet("ppp"))
	config.GlobalRendererFlag.SetLookupFunc(func(cmdPath, flagName string) (string, bool) {
		// fmt.Printf("SetLookupFunc: %s, %s\n", cmdPath, flagName)
		//1. 根据cmdPath选中第几级cli.Context
		currentCmdPath := ""
		var foundCtx *cli.Context
		lineage := ctx.Lineage()
		for i := len(lineage) - 1; i >= 0; i-- {
			c := lineage[i]
			if c == nil || c.Command == nil {
				continue
			}
			if c.Command.Name == "main" {
				if cmdPath == "main" || cmdPath == "" {
					foundCtx = c
					break
				}
				continue
			}
			currentCmdPath += "." + c.Command.Name
			if currentCmdPath == cmdPath {
				foundCtx = c
				break
			}
		}
		if foundCtx == nil {
			//没有找到对应的cli.Context
			return "", false
		}

		//2. 根据flagName选中flag
		if !foundCtx.IsSet(flagName) {
			return "", false
		}
		fv := fmt.Sprintf("%v", foundCtx.Value(flagName))
		return fv, true
	})
}
